/*----------------------------------------------------------------------------
The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the 
License at http://www.mozilla.org/MPL/
	
Software distributed under the License is distributed on 
an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, 
either express or implied. 
See the License for the specific language governing rights and 
limitations under the License.

The Initial Developer of the Original Code is Romain Ecarnot.
Portions created by Initial Developer are Copyright (C) 2010
the Initial Developer. All Rights Reserved.
	
Contributor(s):
	
Unless required by applicable law or agreed to in writing, 
software distributed under the License is distributed on 
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS 
OF ANY KIND, either express or implied.
See the License for the specific language governing permissions 
and limitations under the License.
----------------------------------------------------------------------------*/
package net.customactions.fps 
{
	import com.adobe.fps.distribution;

	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.ErrorEvent;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.net.URLRequest;
	import flash.system.Security;
	import flash.utils.Dictionary;
	import flash.utils.Proxy;
	import flash.utils.flash_proxy;
	
	use namespace flash_proxy;

	/**
	 *  Dispatched during ShareMenu loading progression.
	 *  
	 *  @eventType flash.events.ProgressEvent.PROGRESS
	 */
	[Event(name="progress", type="flash.events.ProgressEvent")]

	/**
	 *  Dispatched when ShareMenu is loaded and available.
	 *  
	 *  @eventType flash.events.Event.COMPLETE
	 */
	[Event(name="complete", type="flash.events.Event")]

	/**
	 *  Dispatched when an error occured during ShareMenu loading.
	 *  
	 *  @eventType flash.events.IOErrorEvent.IO_ERROR
	 */
	[Event(name="ioError", type="flash.events.IOErrorEvent")]

	/**
	 *  Dispatched when ShareMenu is opened.
	 *  
	 *  @eventType flash.display.events.Event.OPEN
	 */
	[Event(name="open", type="flash.events.Event")]

	/**
	 *  Dispatched when ShareMenu is closed.
	 *  
	 *  @eventType flash.display.events.Event.CLOSE
	 */
	[Event(name="close", type="flash.events.Event")]

	/**
	 *  Dispatched when all required properties are not set for before 
	 *  opening ShareMenu.
	 *  
	 *  @eventType flash.events.IOErrorEvent.VERIFY_ERROR
	 */
	[Event(name="verifyError", type="flash.events.IOErrorEvent")]

	/**
	 *  Dispatched when reporting services failed.
	 *  
	 *  @eventType flash.events.ErrorEvent.ERROR
	 */
	[Event(name="error", type="flash.events.ErrorEvent")]

	/**
	 * ADMHelper class offer easy and quick way to use the Adobe Distribution 
	 * Manager Service.
	 * 
	 * <p>More informations on Distribution Manager Service can be found 
	 * here : http://www.adobe.com/flashplatform/services/distribution/</p>
	 * 
	 * <p>The com.adobe.fps.distribution class in included in the SWC version 
	 * of ADMHelper library.</p>
	 * 
	 * @example
	 * <listing>
	 *  //Adobe Distribution Manager Service Partner identifier						
	 *  ADMHelper.PARTNER_ID = "...";
	 * 
	 *  //Creates (and/or retreives) ADMHelper for this application identifier
	 * 	var helper : ADMHelper = ADMHelper.getInstance(CODE_ID);
	 * 	
	 * 	//Defines application specific configuration if needed
	 * 	//helper.configID ="MyConfig";
	 * 	
	 * 	//Distribution properties
	 * 	helper.title = "Distibution Manager Sample";
	 * 	helper.description = "Just a sample of Distribution Manager System";
	 * 	helper.copyright = "Romain Ecarnot";
	 * 	helper.flashURL = "http://.../app.swf";
	 * 	helper.previewURL = "http://.../thumb.png";
	 * 	
	 * 	//Optional, set the Email subject
	 * 	helper.emailSubject = "Discover this incredible application";
	 * 	
	 * 	//Optional, set the Bookmark url
	 * 	helper.bookmarkURL = "http://blog.customactions.net/portfolio";
	 * 	
	 * 	//Use prebuilt Theme UI
	 * 	helper.UIConfig = ADMShareMenuUI.DEEP_BLUE;
	 * 	
	 * 	//FlashVars 
	 * 	helper.addFlashVar("title", "let's discover the reality");
	 * 	helper.addFlashVar("internal", true);
	 * 	helper.addFlashVar("startLevel", 10);
	 * 	
	 * 	//URL Query
	 * 	helper.addURLQuery("lang", "fr");
	 * 	
	 * 	//Enable the reporting service
	 * 	helper.initReporting(this);
	 * 				
	 * 	//Adds listeners for ShareMenu loading events
	 * 	helper.addEventListener(ProgressEvent.PROGRESS, _onMenuProgressHandler);
	 * 	helper.addEventListener(Event.COMPLETE, _onMenuLoadedHandler);
	 * 	helper.addEventListener(IOErrorEvent.IO_ERROR, _onMenuErrorHandler);
	 * 	helper.addEventListener(IOErrorEvent.VERIFY_ERROR, _onMenuPropErrorHandler);
	 * 	
	 * 	//Adds listeners for ShareMenu behaviour events
	 * 	helper.addEventListener(Event.OPEN, _onMenuOpenHandler);
	 * 	helper.addEventListener(Event.CLOSE, _onMenuCloseHandler);
	 * 	
	 * 	//Open ShareMenu
	 * 	helper.openShareMenu();
	 * 	
	 * 	//Track custom event for reporting
	 * 	helper.trackEvent("Just starts at level 0");
	 * </listing>
	 *      
	 * @author Romain Ecarnot (http://blog.customactions.net)
	 */
	dynamic public class ADMHelper extends Proxy implements IEventDispatcher
	{
		//--------------------------------------------------------------------
		// Private properties
		//--------------------------------------------------------------------
		
		/** 
		 * Default content pattern for embeded code.
		 */
		private static const DEFAULT_CONTENT : String = '<OBJECT classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" WIDTH="{0}" HEIGHT="{1}" id="{2}"><PARAM NAME="movie" VALUE="{3}" /><PARAM NAME="quality" VALUE="high" /><PARAM NAME="bgcolor" VALUE="{4}" /><PARAM NAME="flashVars" value="{5}" /><EMBED src="{3}" quality="high"  WIDTH="{0}" HEIGHT="{1}" NAME="{2}" flashVars="{5}" ALIGN="" TYPE="application/x-shockwave-flash" PLUGINSPAGE="http://www.macromedia.com/go/getflashplayer"></EMBED></OBJECT>';

		/**
		 *  Managers repository.
		 */
		private static const _repository : Dictionary = new Dictionary(true);

		/** 
		 * Proxy values identifier list.
		 */
		private var _item : Array;

		/** 
		 * Proxy data storage.
		 */
		private var _data : Object;

		/**
		 * Particular application variant identifier.
		 */
		private var _configID : String;

		/** 
		 * Distribution ShareMenu container.
		 */
		private var _container : MovieClip;

		/**
		 * Application identifier.
		 */
		private var _codeID : String;

		/** 
		 * Distribution ShareMenu module identifier.
		 */
		private var _moduleID : String;

		/**
		 * Instance dispatcher.
		 */
		private var _broadcaster : EventDispatcher;

		/** 
		 * Width of the deployed Flash file.
		 */
		private var _flashWidth : uint;

		/** 
		 * Height of the deployed Flash file.
		 */
		private var _flashHeight : uint;

		/** 
		 * URL of the deployed Flash file.
		 */
		private var _flashURL : String;

		/** 
		 * Background color of the deployed Flash file.
		 */
		private var _flashBackground : uint;

		/**
		 * Optional Flashvars storage.
		 */
		private var _vars : Vector.<VarVO>;

		/**
		 * Optional URL Query storage.
		 */
		private var _queries : Vector.<VarVO>;

		/** 
		 * Indicates if Distribution ShareMenu is already loaded or not.
		 */
		private var _menuLoaded : Boolean;

		/**
		 * Distribution configuration object.
		 */
		private var _ditributionConf : Object;

		/**
		 * Distribution parameters object.
		 */
		private var _ditributionParams : Object;

		
		//--------------------------------------------------------------------
		// Public properties
		//--------------------------------------------------------------------
		
		/**
		 * Adobe Distribution Manager partner identifer.
		 * 
		 * <p>Must be set before any calls.</p>
		 */
		public static var PARTNER_ID : String;

		/**  
		 * Default Giya domain address.
		 * 
		 * @default is cdn.gigya.com
		 */
		public static var GIYA_DOMAIN : String = "cdn.gigya.com";

		/**  
		 * Default Giya wildfireInAS3 url.
		 * 
		 * @default is http://cdn.gigya.com/WildFire/swf/wildfireInAS3.swf?ModuleID=
		 */
		public static var GIYA_LAUNCHER_URL_AS3 : String = "http://cdn.gigya.com/WildFire/swf/wildfireInAS3.swf?ModuleID=";

		
		/**
		 * The Distribution Application Code identifier.
		 */
		public function get codeID() : String
		{
			return _codeID;
		}

		/**
		 * ShareMenu's width.
		 * 
		 * @default 250
		 */
		public function get menuWidth() : uint
		{
			return _data["width"];
		}

		/** @private */
		public function set menuWidth(value : uint) : void
		{
			_data["width"] = value;
		}

		/**
		 * ShareMenu's height.
		 * 
		 * @default 250
		 */
		public function get menuHeight() : uint
		{
			return _data["height"];
		}

		/** @private */
		public function set menuHeight(value : uint) : void
		{
			_data["height"] = value;
		}

		/**
		 * URL of the deployed Flash file.
		 */
		public function get flashURL() : String
		{
			return _flashURL;
		}

		/** @private */
		public function set flashURL(value : String) : void
		{
			_flashURL = value;
		}

		/**
		 * URL of the preview image file.
		 */
		public function get previewURL() : String
		{
			return _data["defaultPreviewURL"];
		}

		/** @private */
		public function set previewURL(value : String) : void
		{
			_data["defaultPreviewURL"] = value;
		}

		/**
		 * Indicates if Gayia ShareMenu use advanced Tracking feature.
		 * 
		 * @default true
		 */
		public function get advancedTracking() : Boolean
		{
			return _data["advancedTracking"];
		}

		/** @private */
		public function set advancedTracking(value : Boolean) : void
		{
			_data["advancedTracking"] = value;
		}

		/**  
		 * @private
		 * 
		 * @default false
		 */
		public function get useFacebookMystuff() : Boolean
		{
			return _data["useFacebookMystuff"];
		}

		/** @private */
		public function set useFacebookMystuff(value : Boolean) : void
		{
			_data["useFacebookMystuff"] = value;
		}

		/**
		 * Application's title.
		 */
		public function get title() : String
		{
			return _data["widgetTitle"];
		}

		/** @private */
		public function set title(value : String) : void
		{
			_data["widgetTitle"] = value;
		}

		/**
		 * Application's description.
		 */
		public function get description() : String
		{
			return _data["widgetDescription"];
		}

		/** @private */
		public function set description(value : String) : void
		{
			_data["widgetDescription"] = value;
		}

		/**
		 * Application's copyright.
		 */
		public function get copyright() : String
		{
			return _data["copyright"];
		}

		/** @private */
		public function set copyright(value : String) : void
		{
			_data["copyright"] = value;
		}

		/**
		 * Application's icon URL.
		 */
		public function get iconURL() : String
		{
			return _data["iconURL"];
		}

		/** @private */
		public function set iconURL(value : String) : void
		{
			_data["iconURL"] = value;
		}

		/**
		 * Application's bookmark URL.
		 */
		public function get bookmarkURL() : String
		{
			return _data["defaultBookmarkURL"];
		}

		/** @private */
		public function set bookmarkURL(value : String) : void
		{
			_data["defaultBookmarkURL"] = value;
		}

		/**
		 * Email's subject.
		 */
		public function get emailSubject() : String
		{
			return _data["emailSubject"];
		}

		/** @private */
		public function set emailSubject(value : String) : void
		{
			_data["emailSubject"] = value;
		}

		/**
		 * Email's body.
		 */
		public function get emailBody() : String
		{
			return _data["emailBody"];
		}

		/** @private */
		public function set emailBody(value : String) : void
		{
			_data["emailBody"] = value;
		}

		/**
		 * ShareMenu User Interface theme.
		 * 
		 * <p>Can use default themes defined in ShareMenuUI class</p>
		 * 
		 * @default clean
		 * 
		 * @see ADMShareMenuUI
		 */
		public function get UIConfig() : String
		{
			return _data["UIConfig"];
		}

		/** @private */
		public function set UIConfig(value : String) : void
		{
			_data["UIConfig"] = value;
		}

		/**
		 * Embed code of the deployed Flash application.
		 */
		public function get embedCode() : String
		{
			return _data["defaultContent"];
		}

		/** @private */
		public function set embedCode(value : String) : void
		{
			_data["defaultContent"] = value;
		}

		/**
		 * Width of the deployed Flash file.
		 */
		public function get flashWidth() : uint
		{
			return _flashWidth;
		}

		/** @private */
		public function set flashWidth(value : uint) : void
		{
			_flashWidth = value;
		}

		/**
		 * Height of the deployed Flash file.
		 */
		public function get flashHeight() : uint
		{
			return _flashHeight;
		}

		/** @private */
		public function set flashHeight(value : uint) : void
		{
			_flashHeight = value;
		}

		/**
		 * Background color of the deployed Flash file.
		 * 
		 * @default 0xFFFFFF;
		 */
		public function get flashBackground() : uint
		{
			return _flashBackground;
		}

		/** @private */
		public function set flashBackground(value : uint) : void
		{
			_flashBackground = value;
		}
		
		/**
		 * Application variant identifier.
		 */
		public function get configID() : String
		{
			return _configID;
		}

		/** @private */
		public function set configID(value : String) : void
		{
			_configID = value;
		}

		
		//--------------------------------------------------------------------
		// Public API
		//--------------------------------------------------------------------
		
		/**
		 * Returns ADMHelper instance using <code>codeID</code> identifier.
		 * 
		 * @param codeID	Application code identifier
		 * 		
		 * @return Instance of ADMHelper for passed-in codeID
		 */	
		public static function getInstance(codeID : String) : ADMHelper
		{
			if ( codeID == null || codeID.length < 1 )
			{
				throw new Error("ADMHelper::getInstance(" + codeID + ") failed!. CodeID is invalid.");
				return null;
			}
			
			if(ADMHelper._repository[codeID] == undefined)
			{
				ADMHelper._repository[codeID] = new ADMHelper(ConstructorAccess.instance, codeID); 	
			}
			
			return ADMHelper._repository[codeID];
		}

		/**
		 * Releases ADMHelper using passed-in codeID identifier.
		 * 
		 * @param codeID	Application code identifier
		 */
		public static function release(codeID : String = null) : Boolean
		{
			if(ADMHelper._repository[codeID] != undefined)
			{
				ADMHelper(ADMHelper._repository[codeID])._clean();
								ADMHelper._repository[codeID] = null;
				delete  ADMHelper._repository[codeID];
					
				return true;
			}
			
			return false;
		}

		/**
		 * Returns <code>true</code> if a ADMHelper exist for 
		 * passed-in <code>codeID</code> identifier.
		 * 
		 * @param codeID	Application code identifier
		 * 
		 * @return <code>true</code> if a ADMHelper exist 
		 * for passed-in <code>codeID</code> identifier
		 */
		public static function hasManager(codeID : String) : Boolean
		{
			return ADMHelper._repository[codeID] != undefined;
		}

		/**
		 * Adds new Flashvar to allow correct Flash embed.
		 * 
		 * @param name	Flashvar name
		 * @param value	Flashvar value
		 * 
		 * @langversion ActionScript 3.0
		 * @playerversion Flash 10
		 */
		public function addFlashVar(name : String, value : *) : void
		{
			_vars.push(new VarVO(name, value));	
		}

		/**
		 * Adds new URL Query to allow correct Flash embed.
		 * 
		 * @param name	Query name
		 * @param value	Query value
		 * 
		 * @langversion ActionScript 3.0
		 * @playerversion Flash 10 
		 */
		public function addURLQuery(name : String, value : *) : void
		{
			_queries.push(new VarVO(name, value));	
		}

		/**
		 * Tracks passed-in event using Distribution reporting feature.
		 * 
		 * <p>The application root must be defined in instance constructor.</p>
		 * 
		 * @param value	Custom event to track
		 * 
		 * @langversion ActionScript 3.0
		 * @playerversion Flash 10
		 */
		public function trackEvent(value : String) : void	
		{
			distribution.services.reports.reportEvent(_ditributionConf, {eventName : value, cid : _getIdentifier(codeID, configID)});	
		}
		
		/**
		 * Opens ShareMenu.
		 * 
		 * <p>If ShareMenu is not yet loaed, loads it first.<br/>
		 * Take a look at events section to know which events are dispatched 
		 * during loading process.</p>
		 * 
		 * @langversion ActionScript 3.0
		 * @playerversion Flash 10
		 */
		public function openShareMenu() : void
		{
			if(_menuLoaded) 
			{
				_container.visible = true; 
				
				_broadcaster.dispatchEvent(new Event(Event.OPEN));
				
				return;
			}
			
			if(!embedCode)
			{
				embedCode = _substitute(DEFAULT_CONTENT, flashWidth, flashHeight, title, _getFlashURL(flashURL, _queries), _hexaToString(_flashBackground), _getFlashVars(_vars, _configID));
			}
			
			var errors : String = _checkStatus();
			if(errors.length > 0)
			{
				_broadcaster.dispatchEvent(new IOErrorEvent(IOErrorEvent.VERIFY_ERROR, false, false, errors));
				
				return;
			}
			
			var loader : Loader = new Loader();
			loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, _onLoadProgressHandler);
			loader.contentLoaderInfo.addEventListener(Event.COMPLETE, _onLoadCompleteHandler);
			loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, _onLoadErrorHandler);
			
			_data["CID"] = _getIdentifier(codeID, configID);
			
			_data["onClose"] = function(...args) : void {
				_container.visible = false;
				loader.content["INIT"]();
				_broadcaster.dispatchEvent(new Event(Event.CLOSE));
			};
			
			var url : String = GIYA_LAUNCHER_URL_AS3 + _moduleID;
			var request : URLRequest = new URLRequest(url);
			_container[_moduleID] = _data;
			
			loader.load(request);
			
			_container.addChild(loader);  
		}

		/**
		 * Closes the ShareMenu.
		 * 
		 * <p>Dispatches a Event.CLOSE event.</p>
		 * 
		 * @langversion ActionScript 3.0
		 * @playerversion Flash 10 
		 */
		public function closeShareMenu() : void	
		{
			if(_menuLoaded && _container.visible)
			{
				_container.visible = false;	
				try
				{
					if(_data["onClose"] is Function) _data["onClose"]();		
				}
				catch(e : Error)
				{
				}
			}
		}

		/**
		 * Returns ShareMenu container
		 * 
		 * @langversion ActionScript 3.0
		 * @playerversion Flash 10 
		 */
		public function getShareMenu() : MovieClip
		{
			return _container;
		}

		/**
		 * Inits Distribution Manager reporting feature.
		 * 
		 * <p>Retreives default application size if not yet set.</p>
		 * 
		 * @param root	Application root object.
		 * 
		 * @langversion ActionScript 3.0
		 * @playerversion Flash 10
		 */
		public function initReporting(root : Sprite) : void
		{
			if(!_ditributionConf)
			{
				if(root.stage)
				{
					if(!_flashWidth) _flashWidth = root.stage.stageWidth;
					if(!_flashHeight) _flashHeight = root.stage.stageHeight;
				}	
				
				_ditributionConf = { mcRoot : root, pid : PARTNER_ID };
				_ditributionParams = { services : "reports", callback : function(response : Object) : void {
					if(response.hadError)
					{
						_broadcaster.dispatchEvent(new ErrorEvent(ErrorEvent.ERROR, false, false, response.errorMessage));
					}
				} 
				};
				
				distribution.load(_ditributionConf, _ditributionParams);
			}	
			else throw new Error("Distribution Manager reporting service already in use.");
		}

		/**
		 * Registers an event listener object with this EventDispatcher object 
		 * so that the listener receives notification of an event.
		 * 
		 * @param type				Type of event
		 * @param listener			The listener function that processes the 
		 * 							event.
		 * @param useCapture		Determines whether the listener works in the 
		 * 							capture phase or the target and bubbling 
		 * 							phases.
		 * 	@param priority			The priority level of the event listener.
		 * 	@param useWeakReference	Determines whether the reference 
		 * 							to the listener is strong or weak.
		 * 							
		 * 	@langversion ActionScript 3.0
		 * 	@playerversion Flash 10
		 */
		public function addEventListener(type : String, listener : Function, useCapture : Boolean = false, priority : int = 0, useWeakReference : Boolean = false) : void
		{
			_broadcaster.addEventListener(type, listener, useCapture, priority, useWeakReference);
		}

		/**
		 * Dispatches an event into the event flow.
		 * 
		 * @param 	event	The Event object that is dispatched into the event 
		 * 					flow. 
		 * 
		 * @return	A value of true if the event was successfully 
		 * 			dispatched.<br/> 
		 * 			A value of false indicates failure or that preventDefault() 
		 * 			was called on the event.
		 * 
		 * @langversion ActionScript 3.0
		 * @playerversion Flash 10
		 */
		public function dispatchEvent(event : Event) : Boolean
		{
			return _broadcaster.dispatchEvent(event);
		}

		/**
		 * Checks whether the EventDispatcher object has any listeners 
		 * registered for a specific type of event.
		 * 
		 * @param	type	Type of event
		 * 
		 * @return	A value of true if a listener of the specified type is 
		 * 			registered; false otherwise.
		 * 			
		 * @langversion ActionScript 3.0
		 * @playerversion Flash 10 			
		 */
		public function hasEventListener(type : String) : Boolean
		{
			return _broadcaster.hasEventListener(type);
		}

		/**
		 * Removes a listener from the EventDispatcher object.<br />
		 * If there is no matching listener registered with the EventDispatcher 
		 * object, a call to this method has no effect.
		 * 
		 * @param type			Type of event
		 * @param listener		The listener object to remove
		 * @param useCapture	Specifies whether the listener was registered 
		 * 						for the capture phase or the target and bubbling 
		 * 						phases.
		 * 						
		 * @langversion ActionScript 3.0
		 * @playerversion Flash 10
		 */
		public function removeEventListener(type : String, listener : Function, useCapture : Boolean = false) : void
		{
			_broadcaster.removeEventListener(type, listener, useCapture);
		}

		/**
		 * Checks whether an event listener is registered with this 
		 * EventDispatcher object or any of its ancestors for the specified 
		 * event type.
		 * 
		 * @param	type	Type of event
		 * 
		 * @return	A value of true if a listener of the specified type will be 
		 * 			triggered; false otherwise.
		 * 			
		 * @langversion ActionScript 3.0
		 * @playerversion Flash 10
		 */
		public function willTrigger(type : String) : Boolean
		{
			return _broadcaster.willTrigger(type);
		}
		
		/**
		 * Returns the string representation of the instance.
		 * 
		 * return A string representation of instance
		 * 
		 * @langversion ActionScript 3.0
		 * @playerversion Flash 10
		 */
		public function toString() : String
		{
			return "ADMHelper[" + PARTNER_ID + "/" + codeID + "]";
		}

		
		//--------------------------------------------------------------------
		// Private methods
		//--------------------------------------------------------------------
		
		/**
		 * @private 
		 * 
		 * Private constructor. Use getInstance(codeID) to create or retreive 
		 * ADMHelper instance.
		 * 
		 * @param codeID	Application code identifier
		 */
		function ADMHelper(access : ConstructorAccess, codeID : String) 
		{
			if (access is ConstructorAccess) 
			{
				_initBase();
				_initDistribution(codeID);
			}
			else throw new Error("ADMHelper instanciation failed!");
		}

		/**
		 * Inits instance properties.
		 */
		private function _initBase() : void
		{
			_data = {};
			
			_vars = new Vector.<VarVO>(); 
			_vars.push(new VarVO("crtr", 1));
			
			_queries = new Vector.<VarVO>(); 
			
			_menuLoaded = false;
			_container = new MovieClip();
			_broadcaster = new EventDispatcher(this);
		}

		/**
		 * Inits basic properties.
		 * 
		 * @param codeID	Application code identifier
		 */
		private function _initDistribution(codeID : String) : void
		{
			if(!PARTNER_ID)
			{
				throw new Error("Distribution Manager PartnerID must be set!");
				return;
			}
			
			Security.allowInsecureDomain(GIYA_DOMAIN);
			Security.allowDomain(GIYA_DOMAIN);
			
			_data["partner"] = PARTNER_ID;
			_codeID = codeID;			
			menuWidth = 250;
			menuHeight = 250;
			advancedTracking = true;
			useFacebookMystuff = false;
			title = "";
			description = "";
			UIConfig = ADMShareMenuUI.CLEAN;
			
			_moduleID = "PostModule" + _codeID;
			
			_flashBackground = 0xFFFFFF;
		}

		/**
		 * Clean instance properties.
		 */
		private function _clean() : void
		{
			_ditributionConf = null;
			_ditributionParams = null;
			
			closeShareMenu();
			
			while(_container.numChildren > 0) _container.removeChildAt(0);
			
			if(_container.parent) _container.parent.removeChild(_container);
			
			_broadcaster = null;
			_data = null;
			_item = null;
			_vars = null;			_queries = null;
		}

		/**
		 * Checks if necessaries properties are defined before opening 
		 * ShareMenu.
		 * 
		 * @return	<code>true</code> if properties are ok, 
		 * 			either <code>false</code>
		 */
		private function _checkStatus() : String
		{
			var errorMessage : String = "";
			
			errorMessage += _validateString(previewURL, "previewURL");			errorMessage += _validateString(flashURL, "flashURL");			errorMessage += _validateString(UIConfig, "UIConfig");			errorMessage += _validateString(title, "title");			errorMessage += _validateString(embedCode, "embedCode");
						errorMessage += _validateNumber(flashWidth, "flashWidth");			errorMessage += _validateNumber(flashHeight, "flashHeight");			errorMessage += _validateNumber(menuWidth, "menuWidth");			errorMessage += _validateNumber(menuHeight, "menuHeight");
			
			return errorMessage;
		}
		
		/**
		 * Triggered during ShareMenu loading progression.
		 * 
		 * <p>Dispatches an ProgressEvent.PROGRESS event.</p>
		 */
		private function _onLoadProgressHandler(event : ProgressEvent) : void
		{
			_broadcaster.dispatchEvent(new ProgressEvent(event.type, event.bubbles, event.cancelable, event.bytesLoaded, event.bytesTotal));
		}

		/**
		 * Triggered when an error occrured during ShareMenu loading 
		 * process.
		 * 
		 * <p>Dispatches an IOErrorEvent.IO_ERROR event.</p>
		 */
		private function _onLoadErrorHandler(event : IOErrorEvent) : void
		{
			_broadcaster.dispatchEvent(new IOErrorEvent(event.type, event.bubbles, event.cancelable, event.text));
			
			_releaseLoader(event.target as LoaderInfo);
			
			_menuLoaded = false;
		}

		/**
		 * Triggered when ShareMenu is loaded.
		 * 
		 * <p>Dispatches an Event.COMPLETE event.</p>
		 */
		private function _onLoadCompleteHandler(event : Event) : void
		{
			_releaseLoader(event.target as LoaderInfo);
			
			_menuLoaded = true;
			
			_broadcaster.dispatchEvent(new Event(Event.COMPLETE));
			_broadcaster.dispatchEvent(new Event(Event.OPEN));
		}

		/**
		 * Releases ShareMenu loader.
		 */
		private function _releaseLoader(info : LoaderInfo) : void
		{
			info.removeEventListener(ProgressEvent.PROGRESS, _onLoadProgressHandler);
			info.removeEventListener(Event.COMPLETE, _onLoadCompleteHandler);
			info.removeEventListener(IOErrorEvent.IO_ERROR, _onLoadErrorHandler);
		}

		/** @private */
		flash_proxy override function callProperty(name : *, ...args) : * 
		{
			throw new Error();
		}

		/** @private */
		flash_proxy override function deleteProperty(name : *) : Boolean 
		{
			return delete _data[name];
		}

		/** @private */
		flash_proxy override function getDescendants(name : *) : * 
		{
			return _data.descendants(name);
		}

		/** @private */
		flash_proxy override function getProperty(name : *) : * 
		{
			return _data[name];
		}

		/** @private */
		flash_proxy override function setProperty(name : *, value : *) : void 
		{
			_data[name] = value;
		}

		/** @private */
		flash_proxy override function hasProperty(name : *) : Boolean 
		{
			return _data.hasOwnProperty(name);
		}

		/** @private */
		flash_proxy override function isAttribute(name : *) : Boolean 
		{
			return !(_data[name] is Function);
		}

		/** @private */
		flash_proxy override function nextNameIndex(index : int) : int 
		{
			if(index == 0) 
			{
				_item = [];
				for (var x:* in _data) _item.push(x); 
			}
                        
			return index < _item.length ? index + 1 : 0;
		}

		/** @private */
		flash_proxy override function nextName(index : int) : String 
		{
			return _item[index - 1];
		}

		/** @private */
		flash_proxy override function nextValue(index : int) : * 
		{
			return _data[_item[index - 1]];
		}

		/**
		 * Returns Hexa color in String representation.
		 */
		private static function _hexaToString( hexa : Number ) : String
		{
			var result : String = hexa.toString(16);
			var len : Number = 6 - result.length;
			while (len--) result = "0" + result;
			return "#" + result.toUpperCase();	
		}

		/**
		 * Substites passed-in argument in source string.
		 */
		private static function _substitute( source : String, ...rest ) : String
		{
			if ( source != null && source.length > 0 )
			{
				var args : Array;
				var length : int = rest.length;
				
				if( length == 1 && rest[0] is Array )
				{
					args = rest[0] as Array;
					length = args.length;
				}
				else args = rest;
				
				for( var i : int = 0;i < length;i += 1 )
				{
					source = source.replace(new RegExp("\\{" + i + "\\}", "g"), args[i]);
				}
			}
			
			return source;
		}

		/**
		 * Returns Flahsvars storage in String representation.
		 */
		private static function _parseProperties(properties : Vector.<VarVO>) : String
		{
			var result : String = "";
			var vVO : VarVO;
			var value : String;
			
			for(var i : uint = 0;i < properties.length;i++)
			{
				vVO = properties[i];
				value = vVO.value;
				
				if(value.hasOwnProperty("toString") && value.toString is Function)
				{
					value = escape(value.toString());
				}
				else value = escape(String(value));
				
				result += vVO.name + "=" + value;
				
				if(i < properties.length - 1) result += "&";
			}
			
			return result;
		}

		/** @private */
		private static function _getFlashURL(url : String, queries : Vector.<VarVO>) : String
		{
			if(queries.length > 0)
			{
				return url + "?" + _parseProperties(queries);
			}
			
			return url;
		}

		/** @private */
		private static function _getFlashVars(vars : Vector.<VarVO>, config : String) : String
		{
			var result : String = _parseProperties(vars);
			
			if(config && config.length > 0)
			{
				result += ("&gig_cfg=" + config);
			}
			
			return result;
		}

		/** @private */
		private static function _getIdentifier(code : String, config : String) : String
		{
			if(config && config.length > 0)
			{
				return code + "/" + config;
			}
			
			return code;
		}
		
		/**
		 * Validates passed-in string.
		 */
		private static function _validateString(source : String, id : String) : String
		{
			if(!source || source.length < 1)
			{
				 return _substitute(LocalError.getTranslation(id), source) + ";";
			}
			return "";
		}
		
		/**
		 * Validates passed-in number.
		 */
		private static function _validateNumber(source : Number, id : String) : String
		{
			if(isNaN(source) || source < 1)
			{
				return _substitute(LocalError.getTranslation(id), source) + ";";
			}
			return "";
		}
	}
}

import flash.system.Capabilities;

internal class VarVO
{
	/** Flashvar name. */
	public var name : String;

	/** Flashvar value. */
	public var value : *;

	
	/**
	 * Creates instance
	 * 
	 * @param name	Flashvar name
	 * @param value	Flashvar value
	 */
	public function VarVO(name : String, value : *) 
	{
		this.name = name;
		this.value = value;
	}
}

internal class ConstructorAccess 
{
	static public const instance : ConstructorAccess = new ConstructorAccess();
}

internal class LocalError
{
	private static var ADMHelperNS : Namespace = _initNS();
	
	private static var translations : XML;
	
	private static function _initNS() : Namespace
	{
		translations = <locale xmlns:fr="http://www.customactions.net/fr" xmlns:en="http://www.customactions.net/en">
		    <fr:string id="previewURL"><![CDATA[L'URL de prévisualisation n'est pas définie.({0})]]></fr:string>
			<en:string id="previewURL"><![CDATA[Preview URL is not defined.({0})]]></en:string>
			
			<fr:string id="flashURL"><![CDATA[L'URL de l'application Flash n'est pas définie.({0})]]></fr:string>
			<en:string id="flashURL"><![CDATA[Flash URL is not defined.({0})]]></en:string>
			
			<fr:string id="UIConfig"><![CDATA[La configuration du menu n'est pas définie.({0})]]></fr:string>
			<en:string id="UIConfig"><![CDATA[ShareMenu UI configuration is not.({0})]]></en:string>
			
			<fr:string id="title"><![CDATA[Le titre de l'application n'est pas défini.({0})]]></fr:string>
			<en:string id="title"><![CDATA[Application's title is not defined.({0})]]></en:string>
			
			<fr:string id="embedCode"><![CDATA[Le code embarqué de l'application n'est pas défini.({0})]]></fr:string>
			<en:string id="embedCode"><![CDATA[Embed code is not defined.({0})]]></en:string>
			
			<fr:string id="flashWidth"><![CDATA[La largeur de l'application n'est pas correcte.({0})]]></fr:string>
			<en:string id="flashWidth"><![CDATA[Application's width is not valid.({0})]]></en:string>
			
			<fr:string id="flashHeight"><![CDATA[La hauteur de l'application n'est pas correcte.({0})]]></fr:string>
			<en:string id="flashHeight"><![CDATA[Application's height is not valid.({0})]]></en:string>
			
			<fr:string id="menuWidth"><![CDATA[La hauteur du ShareMenu n'est pas correcte.({0})]]></fr:string>
			<en:string id="menuWidth"><![CDATA[ShareMenu's width is not valid.({0})]]></en:string>
			
			<fr:string id="menuHeight"><![CDATA[La hauteur du ShareMenu n'est pas correcte.({0})]]></fr:string>
			<en:string id="menuHeight"><![CDATA[ShareMenu's height is not valid.({0})]]></en:string>
		</locale>; 
		
		var uri : String = "http://www.customactions.net/";
		var local : String = Capabilities.language;
		var ns : Namespace = new Namespace(uri + local);
		var len : uint = translations.namespaceDeclarations().length;
		var found : Boolean = false;
		
		for(var i : uint = 0;i < len;i++)
		{
			if(translations.namespaceDeclarations()[i].uri == ns.uri)
			{
				found = true;
				break;
			}
		}
		
		if(!found) ns = new Namespace(uri + "en");
		
		return ns;
	}
	
	/**
	 * Retreives error message using environement language.
	 */
	public static function getTranslation(key : String) : String
	{
		return translations.ADMHelperNS::string.( @id == key ).toString();
	}
}